package org.artifact.core.plugin.akka;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Cancellable;
import akka.actor.Props;
import com.typesafe.config.ConfigFactory;
import org.artifact.core.lang.AbstractPlugin;
import scala.concurrent.Await;
import scala.concurrent.duration.Duration;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class AkkaPlugin extends AbstractPlugin {
    //	static final ActorManager manager = new DefaultActorManager();
    static ActorSystem system = null;

    static volatile boolean start = false;

    private Map<Class, Map<Serializable, ActorRef>> actors = new ConcurrentHashMap<>();

    @Override
    public boolean start() {
        Map config = new HashMap();
        // 避免虚拟机停止自动停止
        config.put("akka.coordinated-shutdown.terminate-actor-system", "off");
        config.put("akka.coordinated-shutdown.run-by-jvm-shutdown-hook", "off");
        config.put("akka.cluster.run-coordinated-shutdown-when-down", "off");
        // 避免严重错误停止虚拟机
        config.put("akka.jvm-exit-on-fatal-error", "off");

        system = ActorSystem.create("LocalSystem", ConfigFactory.parseMap(config));
        start = true;
        return true;
    }

    @Override
    public boolean stop() {
        try {
            Await.ready(system.terminate(), Duration.create(3, TimeUnit.MINUTES));
            start = false;
        } catch (InterruptedException | TimeoutException e) {
            e.printStackTrace();
        }
        return true;
    }

    /**
     * 创建Actor
     */
    public ActorRef getActor(Serializable actorName, Class actorCalss, Object... objects) {
        Map<Serializable, ActorRef> groupActors = actors.computeIfAbsent(actorCalss, key -> new ConcurrentHashMap<>());
        return groupActors.computeIfAbsent(actorName, key -> system.actorOf(Props.create(actorCalss, objects), actorName.toString()));
    }

    /**
     * 创建Actor
     */
    public ActorRef getActor(Class actorClass, Object... objects) {
        return getActor("default", actorClass, objects);
    }


    /**
     * 延迟执行
     *
     * @return
     */
    public Cancellable scheduleOnce(ActorRef actorRef, long milliseconds, Runnable msg) {
        Cancellable cancellable = system.scheduler().scheduleOnce(Duration.create(milliseconds, TimeUnit.MILLISECONDS), actorRef, msg, system.dispatcher(), ActorRef.noSender());
        return cancellable;
    }

    /**
     * 定时执行
     *
     * @return
     */
    public Cancellable schedule(ActorRef actorRef, long initialDelay, long interval, Runnable msg) {
        Cancellable cancellable = system.scheduler().schedule(Duration.create(initialDelay, TimeUnit.MILLISECONDS), Duration.create(interval, TimeUnit.MILLISECONDS), actorRef, msg, system.dispatcher(), ActorRef.noSender());
        return cancellable;
    }

//    /** 创建Actor */
//    public ActorRef createActor(String groupName,String actorName, Class actorCalss, Object...objects){
//        Map<String, ActorRef> groupActors = actors.computeIfAbsent(groupName,key -> new ConcurrentHashMap<>());
//        ActorRef actorRef = getActor(groupName,actorName);
//        if (actorRef != null){
//            throw LogicUtil.error(-1,"Actor已存在 GroupName = " + groupName +" ActorName = " + actorName);
//        }else {
//            actorRef = system.actorOf(Props.create(actorCalss,objects), groupName + "/" + actorName);
//            groupActors.put(actorName,actorRef);
//        }
//        return actorRef;
//    }
//
//    /** 创建Actor */
//    public ActorRef createActor(String groupName, Class actorCalss, Object...objects){
//        return createActor(groupName,"default",actorCalss,objects);
//    }
//
//    public ActorRef getActor(String groupName,String actorName){
//        Map<String, ActorRef> groupActors = actors.get(groupName);
//        if (groupActors == null){
//            return groupActors.get(actorName);
//        }
//        return null;
//    }
//
//    public ActorRef getActor(String groupName){
//        return getActor(groupName,"default");
//    }


//    public static ActorSystem getProxy(){
//        if (start) {
//            return system;
//        }else {
//            throw ToolError.newLogicError(ArtifactErrorCode.PLUGIN_NOT_INITIALIZED);
//        }
//    }
}
